use serde::{Deserialize, Serialize};
use serde_json::json;
use sha2::{Digest, Sha256};
use std::time::{SystemTime, UNIX_EPOCH};

// 交易结构
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Transaction {
    sender: String,
    recipient: String,
    amount: u64,
}

// 区块结构
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Block {
    index: u64,
    previous_hash: String,
    timestamp: u64,
    transactions: Vec<Transaction>,
    nonce: u64,
    hash: String,
}

impl Block {
    // 创建新区块
    fn new(index: u64, previous_hash: String, transactions: Vec<Transaction>) -> Self {
        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("时间获取失败")
            .as_secs();
        
        let mut block = Block {
            index,
            previous_hash,
            timestamp,
            transactions,
            nonce: 0,
            hash: String::new(),
        };
        
        block.hash = block.calculate_hash();
        block
    }
    
    // 计算区块哈希
    fn calculate_hash(&self) -> String {
        let block_data = json!({
            "index": self.index,
            "previous_hash": self.previous_hash,
            "timestamp": self.timestamp,
            "transactions": self.transactions,
            "nonce": self.nonce
        });
        
        let block_string = serde_json::to_string(&block_data).expect("JSON序列化失败");
        let mut hasher = Sha256::new();
        hasher.update(block_string.as_bytes());
        let result = hasher.finalize();
        format!("{:x}", result)
    }
    
    // 挖矿函数
    fn mine_block(&mut self, difficulty: u8) {
        let target = "0".repeat(difficulty as usize);
        
        while !self.hash.starts_with(&target) {
            self.nonce += 1;
            self.hash = self.calculate_hash();
        }
        
        println!("区块已挖出! 哈希值: {}", self.hash);
    }
}

// 区块链结构
struct Blockchain {
    chain: Vec<Block>,
    difficulty: u8,
    pending_transactions: Vec<Transaction>,
    mining_reward: u64,
}

impl Blockchain {
    // 创建新的区块链
    fn new(difficulty: u8) -> Self {
        let mut blockchain = Blockchain {
            chain: Vec::new(),
            difficulty,
            pending_transactions: Vec::new(),
            mining_reward: 100,
        };
        
        // 创建创世区块
        blockchain.chain.push(blockchain.create_genesis_block());
        blockchain
    }
    
    // 创建创世区块
    fn create_genesis_block(&self) -> Block {
        let genesis_transaction = Transaction {
            sender: "Genesis".to_string(),
            recipient: "System".to_string(),
            amount: 0,
        };
        
        Block::new(0, "0".to_string(), vec![genesis_transaction])
    }
    
    // 获取最新区块
    fn get_latest_block(&self) -> &Block {
        self.chain.last().expect("区块链为空")
    }
    
    // 添加交易
    fn add_transaction(&mut self, transaction: Transaction) -> bool {
        if transaction.sender.is_empty() || transaction.recipient.is_empty() {
            println!("交易必须包含发送方和接收方");
            return false;
        }
        
        // 在实际应用中，这里还需要验证交易的有效性
        self.pending_transactions.push(transaction.clone());
        println!("交易已添加: {:#?}", transaction);
        true
    }
    
    // 挖矿并添加新区块
    fn mine_pending_transactions(&mut self, miner_address: &str) -> u64 {
        // 添加矿工奖励交易
        let reward_transaction = Transaction {
            sender: "system".to_string(),
            recipient: miner_address.to_string(),
            amount: self.mining_reward,
        };
        self.pending_transactions.push(reward_transaction);
        
        // 创建新区块
        let last_block = self.get_latest_block();
        let mut new_block = Block::new(
            last_block.index + 1,
            last_block.hash.clone(),
            self.pending_transactions.clone(),
        );
        
        // 挖矿
        new_block.mine_block(self.difficulty);
        
        // 添加到链上
        self.chain.push(new_block.clone());
        
        // 清空待处理交易
        self.pending_transactions.clear();
        
        println!("区块已添加到链上! 索引: {}", new_block.index);
        new_block.index
    }
    
    // 获取地址余额
    fn get_balance_of_address(&self, address: &str) -> u64 {
        let mut balance: u64 = 0;
        
        for block in &self.chain {
            for transaction in &block.transactions {
                if transaction.sender == address {
                    balance = balance.saturating_sub(transaction.amount);
                }
                if transaction.recipient == address {
                    balance = balance.saturating_add(transaction.amount);
                }
            }
        }
        
        balance
    }
    
    // 验证区块链是否有效
    fn is_chain_valid(&self) -> bool {
        for i in 1..self.chain.len() {
            let current_block = &self.chain[i];
            let previous_block = &self.chain[i-1];
            
            // 验证当前区块哈希
            if current_block.hash != current_block.calculate_hash() {
                println!("区块 {} 的哈希无效", i);
                return false;
            }
            
            // 验证区块链接
            if current_block.previous_hash != previous_block.hash {
                println!("区块 {} 与前一个区块的链接无效", i);
                return false;
            }
        }
        
        true
    }
}

fn main() {
    // 创建区块链实例
    let mut my_coin = Blockchain::new(3); // 较低难度用于演示
    
    println!("挖掘第一个区块...");
    my_coin.mine_pending_transactions("miner-address");
    
    println!("\n挖掘第二个区块...");
    // 添加测试交易
    my_coin.add_transaction(Transaction {
        sender: "address1".to_string(),
        recipient: "address2".to_string(),
        amount: 50,
    });
    
    my_coin.add_transaction(Transaction {
        sender: "address2".to_string(),
        recipient: "address1".to_string(),
        amount: 25,
    });
    
    my_coin.mine_pending_transactions("miner-address");
    
    // 验证区块链
    println!("\n区块链是否有效? {}", my_coin.is_chain_valid());
    
    // 查看余额
    println!("\n矿工地址的余额: {}", my_coin.get_balance_of_address("miner-address"));
    println!("address1的余额: {}", my_coin.get_balance_of_address("address1"));
    println!("address2的余额: {}", my_coin.get_balance_of_address("address2"));
    
    // 尝试篡改区块链
    println!("\n尝试篡改区块链...");
    // 注意：在Rust中我们不能直接修改区块链中的交易，因为区块链是不可变的
    // 这里只是展示验证机制
    println!("注意：在Rust实现中，区块链的结构设计更加安全，直接篡改更加困难");
    
    // 再次验证区块链
    println!("区块链是否有效? {}", my_coin.is_chain_valid());
}